﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Crm.Sdk.Messages;
using System.Threading;
using Microsoft.Xrm.Sdk;

namespace Email_Validator
{
    /// <summary>
    /// Interaction logic for ResultWindow.xaml
    /// </summary>
    public partial class ResultWindow : Window
    {

        private EmailMessage _email;

        public EmailMessage Email
        {
            get { return _email; }
            set { _email = value; }
        }

        private crmauthinfo _crmAuth;

        public crmauthinfo CrmAuth
        {
            get { return _crmAuth; }
            set { _crmAuth = value; }
        }

        private exchangeauthinfo _exchangeAuth;

        public exchangeauthinfo ExchangeAuth
        {
            get { return _exchangeAuth; }
            set { _exchangeAuth = value; }
        }

        private CheckIncomingEmailRequest _checkRequest;
        private CheckIncomingEmailResponse _checkResponse;

        public bool UsedExtraProperties
        {
            get { return _usedExtraProperties; }
            set { _usedExtraProperties = value; }
        }

        private bool _usedExtraProperties;

        public ResultWindow(crmauthinfo crmauth, exchangeauthinfo exchangeauth, string title, EmailMessage email, bool useextraproperties)
        {
            CrmAuth = crmauth;
            ExchangeAuth = exchangeauth;
            Email = email;
            UsedExtraProperties = useextraproperties;
            InitializeComponent();
            Title = "Validation Result - " + title;
            rtbInformation.IsReadOnly = true;
            Thread checkincomingemailthread = new Thread(new ThreadStart(PerformCheckIncomingEmailRequest));
            checkincomingemailthread.SetApartmentState(ApartmentState.STA);
            checkincomingemailthread.Start();
        }

        private void PerformCheckIncomingEmailRequest()
        {
            try
            {
                CheckIncomingEmailRequest checkrequest = new CheckIncomingEmailRequest();
                checkrequest.Bcc = GetAddresses(Email.BccRecipients);
                checkrequest.Cc = GetAddresses(Email.CcRecipients);
                checkrequest.From = Email.From.Address;
                checkrequest.MessageId = Email.InternetMessageId;
                checkrequest.Subject = Email.Subject;
                checkrequest.To = GetAddresses(Email.ToRecipients);
                if (UsedExtraProperties)
                {
                    checkrequest.ExtraProperties = ConversationIndexUtility.GetExtraProperties(Email);
                }

                //Accounting for race condition...
                if (CrmAuth.CrmService == null)
                {
                    CrmAuth.GetOrgProxy(CrmAuth.OrgDetail);
                }

                _checkRequest = checkrequest;
               _checkResponse = (CheckIncomingEmailResponse)CrmAuth.CrmService.Execute(checkrequest);

                this.Dispatcher.Invoke((Action)(() =>
                {
                    SetFormProperties();
                }));

            }

            catch (Exception ex)
            {
                this.Dispatcher.Invoke((Action)(() =>
                {
                    SetErrorStatus(ex);
                }));
                
                MessageBox.Show(MainWindow.GetErrorDetail(ex), "Exception during PerformCheckIncomingEmailRequest()");
            }
        }

        private string GetAddresses(EmailAddressCollection recipients)
        {
            StringBuilder addresses = new StringBuilder();
            foreach (var recipient in recipients)
            {
                addresses.Append(recipient.Address);
                addresses.Append(";");
            }
            return addresses.ToString();
        }

        private void SetErrorStatus(Exception ex)
        {
            PopulateRTB("Error during CheckIncomingEmailRequest()\n\n" + ex.StackTrace, ValidationReasonCode.Unknown);
        }

        private void SetFormProperties()
        {
            promoteLblvalue.Content = _checkResponse.ShouldDeliver.ToString();
            ValidationReasonCode code = (ValidationReasonCode)_checkResponse.ReasonCode;
            reasoncodeLblvalue.Content = code.ToString();
            switch (code)
            {
                case ValidationReasonCode.Unknown:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("Unknown", code);
                    break;

                case ValidationReasonCode.Duplicate:
                    PopulateRTB("This e-mail message has already been promoted to CRM.", code);
                    break;

                case ValidationReasonCode.NoCorrelationMatch:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("Correlation was attempted but did not map to a prior CRM message.", code);
                    break;

                case ValidationReasonCode.CorrelationMatch:
                    PopulateRTB("Correlation was attempted and found a qualifying message for promotion.", code);
                    break;

                case ValidationReasonCode.NoRecipientMatch:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("None of the recipients of the e-mail are users or queues in CRM", code);
                    break;

                case ValidationReasonCode.InternalEmailReject:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("E-mail is considered internal communication between users or queues.", code);
                    break;

                case ValidationReasonCode.SenderMatch:
                    PopulateRTB("E-mail was accepted because a recipient is configured to promote e-mails received from the sender.", code);
                    break;

                case ValidationReasonCode.AcceptAll:
                    PopulateRTB("Email was accepted because a recipient accepts all emails.", code);
                    break;

                case ValidationReasonCode.InvalidSender:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("The sender email address could not be found or is invalid", code);
                    break;

            }

            //ExtensionMethods.Refresh(this);
        }

        private void PopulateRTB(string message, ValidationReasonCode code)
        {
            FlowDocument flowdoc = new FlowDocument();
            Paragraph paragraph = new Paragraph();
            paragraph.Inlines.Add(new Run(message));
            flowdoc.Blocks.Add(paragraph);
            if (!UsedExtraProperties && code == ValidationReasonCode.NoCorrelationMatch)
            {
                Paragraph sssmessage = new Paragraph();
                sssmessage.Inlines.Add(new Run("Email correlation did not use In-Reply-To or ConversationIndex. To attempt correlation using these properties, switch to Server Side Synchronization and try again."));
                flowdoc.Blocks.Add(sssmessage);
            }
            Paragraph requestprops = SetRequestProperties();
            flowdoc.Blocks.Add(requestprops);
            rtbInformation.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
            rtbInformation.Document = flowdoc;
        }

        private Paragraph SetRequestProperties()
        {
            Paragraph paragraph = new Paragraph();
            paragraph.Inlines.Add(new Bold(new Run("Request Properties:\n\n")));
            paragraph.Inlines.Add(new Run(BuildProperties()));
            return paragraph;
        }

        private string BuildProperties()
        {
            StringBuilder properties = new StringBuilder();
            properties.Append("Subject:  ").Append(_checkRequest.Subject).Append("\n");
            properties.Append("To:  ").Append(_checkRequest.To).Append("\n");
            properties.Append("From: ").Append(_checkRequest.From).Append("\n");
            properties.Append("CC: ").Append(_checkRequest.Cc).Append("\n");
            properties.Append("BCC: ").Append(_checkRequest.Bcc).Append("\n");
            properties.Append("MessageId: ").Append(_checkRequest.MessageId).Append("\n");
            if (UsedExtraProperties)
            {
                if (_checkRequest.ExtraProperties.Attributes.ContainsKey("conversationindex"))
                {
                    properties.Append("ConversationIndex: ").Append(_checkRequest.ExtraProperties.Attributes["conversationindex"]).Append("\n");
                }
                if (_checkRequest.ExtraProperties.Attributes.ContainsKey("inreplyto"))
                {
                    properties.Append("In-Reply-To: ").Append(_checkRequest.ExtraProperties.Attributes["inreplyto"]).Append("\n");
                }
            }
            return properties.ToString();
        }

        private void promoteBtn_Click(object sender, RoutedEventArgs e)
        {

        }
    }

    public enum ValidationReasonCode
    {
        Unknown = -1,
        Duplicate = 0,
        NoCorrelationMatch = 1,
        CorrelationMatch = 2,
        NoRecipientMatch = 3,
        InternalEmailReject = 4,
        SenderMatch = 5,
        AcceptAll = 6,
        InvalidSender = 7
    }
}
